package net.chathu.airgw.model.conn 
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.media.Sound;
	import flash.net.Socket;
	import flash.utils.ByteArray;
	import flash.utils.Endian;
	import net.chathu.airgw.Config;
	import net.chathu.airgw.model.handler.GWPacketProcessor;
	import net.chathu.airgw.packets.redirect.Sendable;
	import net.chathu.airgw.packets.redirect.VersionPacket;
	import net.chathu.airgw.Soul;

	/**
	 * ...
	 * @author ze
	 */
	
	[Event(name = "close", type = "flash.events.Event")] // a kapcsolat bezarodott
	[Event(name = "connect", type = "flash.events.Event")]
	[Event(name = "ready", type = "net.chathu.airgw.event.DataSendEvent")]
	[Event(name = "startchat", type = "net.chathu.airgw.event.DataSendEvent")]
	[Event(name = "message", type = "net.chathu.airgw.event.DataSendEvent")]
	
	
	public class GWConnection extends EventDispatcher
	{
		
		private var socket:Socket;
		private var host:String;
		private var port:int;
		private var owner:Soul;
		
		public var connectToChat:Boolean;
		private var readBuffer:ByteArray;
		
		
		public function GWConnection(owner:Soul,host:String, port:int, connectToChat:Boolean=true) 
		{
			this.owner = owner;
			this.host = host;
			this.port = port;
			this.connectToChat = connectToChat;
			
			readBuffer = new ByteArray();
			readBuffer.endian = Endian.LITTLE_ENDIAN;
			//connect(); //called manully
		}
		
			
		public function connect():Boolean
		{
			if (!socket)
			{
				socket = new Socket();
				socket.addEventListener(Event.CLOSE, onSocketClose);
				socket.addEventListener(Event.CONNECT, onSocketConnect);
				socket.addEventListener(IOErrorEvent.IO_ERROR, onSocketIOError);
				socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSocketSecurityError);
				socket.addEventListener(ProgressEvent.SOCKET_DATA, onData);
				socket.connect(host, port);
				return true;
			} else {
				return false;
			}
		}
		
		public function disconnect():Boolean
		{
			if (socket)
			{
				if (socket.connected)
				{
					socket.close();
					return true;
				} else {
					return false;
				}
			} else {
				return false;
			}
		}
		
		
		private function onSocketClose(event:Event):void
		{
			trace("onSocketClose");
		}
		
		private function onSocketConnect(event:Event):void
		{
			trace("onSocketConnect");
			dispatchEvent( new Event(Event.CONNECT));
			sendRedirectorPacket(new VersionPacket(Config.REDIRECTOR_VERSION_INFO));
		}
		
		private function onSocketIOError(event:Event):void
		{
			trace("onSocketIOError");
		}
		
		private function onSocketSecurityError(event:Event):void
		{
			trace("onSocketSecurityError");
		}
		
		private function onData(event:Event):void
		{
			trace("onData: ");

			readBuffer.position += readBuffer.bytesAvailable; //a biztonsag kedveert
			
			if (socket.bytesAvailable > 0)
			{
				//A poziciot visszaallitja!(azt hiszem..)
				socket.readBytes(readBuffer,readBuffer.position,socket.bytesAvailable);
			}
			//trace("RB pos: " + readBuffer.position);
			//ByteArrayDump.dump(readBuffer);
			readBuffer.position = 0;
			
			var recreateBuffer:Boolean = false;
			var packetRead:Boolean;
			do {
				packetRead = false;
				if (readBuffer.bytesAvailable > 2)
				{
					var hi:int = (readBuffer.readByte()+256)%256;
					var lo:int = (readBuffer.readByte()+256)%256;
					/*if (hi < 0 || lo < 0) {
						trace("SOCKET CLOSE DETECTED: " + hi + " / " +lo);
						break;
					}*/
					var length:int = hi * 256 + lo;
					//trace(" LEN: " + length + " REM: " + readBuffer.bytesAvailable + " POS: " + readBuffer.position);
					if (readBuffer.bytesAvailable >= length)
					{
						var cmd:ByteArray = new ByteArray();
						readBuffer.readBytes(cmd, 0, length);
						
						GWPacketProcessor.processGWPacket(this, cmd);
						
						packetRead = true;
						recreateBuffer = true;
					} else {
						readBuffer.position -= 2; //reset read position
					}
				}
			} while (packetRead);
			
			if (recreateBuffer)
			{
				//remove old buffer, create new with the remaining data
				//trace("creating new readbuffer with length:" + readBuffer.bytesAvailable);
				var newReadBuffer:ByteArray = new ByteArray();
				newReadBuffer.endian = Endian.LITTLE_ENDIAN;
				readBuffer.readBytes(newReadBuffer, 0, readBuffer.bytesAvailable);
				readBuffer = newReadBuffer;
			}
			
		}
		
		/*private function send(message:String):void
		{
			trace("C>>" + message);
			socket.writeMultiByte(message+"\r\n", "UTF-8");
			socket.flush();
		}*/
		
		public function sendRedirectorPacket(packet:Sendable):void
		{
			sendPacket(packet.getData(), 0x01);
		}
		
		public function sendChatPacket(data:ByteArray):void
		{
			sendPacket(data, 0x02);
		}
		
		public function sendClientPacket(msg:String):void
		{
			trace("<<C:" + msg);
			var data:ByteArray = new ByteArray();
			data.endian = Endian.LITTLE_ENDIAN;
			data.writeUTFBytes(msg);
			sendPacket(data, 0x03);
		}
		
		
		
		private function sendPacket(data:ByteArray, origin:int):void
		{
			//trace("SEND DUMP:");
			//ByteArrayDump.dump(data);
			data.position = 0; //a biztonsag kedveert
			
			var finalLength:int = data.bytesAvailable +1;
			
			socket.writeByte((finalLength >> 8) & 0xFF);
			socket.writeByte(finalLength & 0xFF);
			socket.writeByte(origin);
			socket.writeBytes(data,0,data.bytesAvailable);
			socket.flush();
		}

		public function get soul():Soul
		{
			return owner;
		}
		
	}

}